﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace COFE.Core.Utils
{
    //http://refactormycode.com/codes/945-cached-ienumerable-t
    /// <summary>
    /// Wraps an IEnumerable<typeparamref name="T"/> and 
    /// provides a thread-safe means of caching the values.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class ThreadSafeCachedEnumerable<T> : IEnumerable<T>
    {
        private IEnumerator<T> baseEnumerator;
        private IList<T> cachedItems = new List<T>();
        public bool Caching = false;

        public ThreadSafeCachedEnumerable(IEnumerable<T> enumerable)
        {            
            this.baseEnumerator = enumerable.GetEnumerator();
        }

        bool CacheNextItem(int currentIndex)
        {
            lock (baseEnumerator)
            {
                Caching = true;
                while (currentIndex >= this.cachedItems.Count)
                {
                    if (!this.baseEnumerator.MoveNext())
                    {
                        Caching = false;
                        return false;
                    }
                    this.cachedItems.Add(this.baseEnumerator.Current);
                }
            }
            return true;
        }

        public IEnumerator<T> GetEnumerator()
        {
            int currentIndex = 0;

            while (currentIndex < this.cachedItems.Count
                    || CacheNextItem(currentIndex))
            {
                yield return this.cachedItems[currentIndex++];
            }
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }
}
